/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ClassDeclaration, SourceFile } from 'ts-morph';
import { ClassAnalysis, PropertyAnalysis, Logger, PropertyKind } from '../../..';
import { ImportManager } from '../shared/ImportManager';
import SerializationPathUtil from '../../../utils/SerializationPathUtil';
import { ConversionDirection } from '../../../handlers/ITypeHandler';
import { TypeHandlerRegistry } from '../../../handlers';
import { MergedSendableClassGenerator } from './MergedSendableClassGenerator';
import { CustomError, ErrorCodes } from '../../../utils/CustomError';
import { TsMorphUtil } from '../../../utils/TsMorphUtil';

export class OriginalClassGenerator {
  private readonly importManager: ImportManager;
  private readonly mergedSendableGenerator: MergedSendableClassGenerator;

  constructor(importManager: ImportManager) {
    this.importManager = importManager;
    this.mergedSendableGenerator = new MergedSendableClassGenerator();
  }

  generate(outputSourceFile: SourceFile, originalSourceFile: SourceFile, results: ClassAnalysis[]): void {
    this.registerImports();

    // 1. 获取原始源文件的完整内容并移除原始import语句
    const contentWithoutImports = this.copySourceFileContentWithoutImports(originalSourceFile);

    // 2. 创建临时源文件进行AST操作
    const tempSourceFile = TsMorphUtil.getProject().createSourceFile('temp.ts', contentWithoutImports, {
      overwrite: true
    });

    for (const result of results) {
      const className = result.className;
      // 3. 找到目标类
      const targetClass = tempSourceFile.getClassOrThrow(className);

      if (result.canMerge && result.decorators.serializable?.generateSendable) {
        this.importManager.registerArkTSImports(['lang']);
        this.mergedSendableGenerator.generate(targetClass, result);
      } else {
        this.addITSerializableInterface(targetClass);
        this.addStaticSerialName(targetClass, result);
        this.generateConvertToSendableMethod(targetClass, result);
        this.generateToJsonMethod(targetClass, result);
      }
    }

    // 8. 将修改后的内容写入目标文件
    outputSourceFile.addStatements(tempSourceFile.getFullText());
  }

  private copySourceFileContentWithoutImports(originalSourceFile: SourceFile): string {
    const originalFilePath = originalSourceFile.getFilePath();
    const originalDir = SerializationPathUtil.dirname(originalFilePath);

    // 创建临时源文件用于AST操作
    const tempSourceFile = TsMorphUtil.getProject().createSourceFile(
      'temp-original.ts',
      originalSourceFile.getFullText(),
      {
        overwrite: true
      }
    );

    // 移除所有import声明
    const importDeclarations = tempSourceFile.getImportDeclarations();
    importDeclarations.forEach((importDecl) => {
      const specifier = importDecl.getModuleSpecifierValue();
      const names = importDecl.getNamedImports().map((names) => names.getName());
      const defaultImport = importDecl.getDefaultImport();

      const importOriginAbs = SerializationPathUtil.pathResolve(originalDir, specifier);
      if (SerializationPathUtil.exist(importOriginAbs + '.ets')) {
        // 路径存在，使用模块化路径计算
        const importOriginAbsWithExt = importOriginAbs + '.ets';
        names.forEach((name) => {
          this.importManager.registerCustomTypeImport(importOriginAbsWithExt, name);
        });
        if (defaultImport) {
          this.importManager.registerDefaultImport(importOriginAbsWithExt, defaultImport.getText());
        }
      } else {
        // 不存在该路径，说明可能为包名，暂时不动
        names.forEach((name) => {
          this.importManager.registerCustomImport(specifier, name);
        });
        if (defaultImport) {
          this.importManager.registerDefaultImport(specifier, defaultImport.getText());
        }
      }
      // 先删除源文件导入，统一注册到importManger中处理
      importDecl.remove();
    });

    const contentWithoutImports = tempSourceFile.getFullText();

    if (!contentWithoutImports || contentWithoutImports.trim().length === 0) {
      throw new CustomError(`Source file content is empty for ${originalFilePath}`, ErrorCodes.INVALID_FILE_CONTENT);
    }

    Logger.debug(`成功拷贝 ${originalFilePath} 文件内容并替换import语句`);
    return contentWithoutImports;
  }

  private addITSerializableInterface(classDecl: ClassDeclaration): void {
    // 检查是否已经实现了接口
    const existingImplements = classDecl.getImplements().map((impl) => impl.getText());
    if (existingImplements.some((impl) => impl.includes('ITSerializable'))) {
      Logger.warn(`类 ${classDecl.getName()} 已经实现了ITSerializable接口, 跳过接口添加`);
      return;
    }

    // 添加接口实现
    classDecl.addImplements('ITSerializable');
    Logger.debug(`为类 ${classDecl.getName()} 添加ITSerializable接口实现`);
  }

  private addStaticSerialName(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    // 添加静态属性
    classDecl.addProperty({
      name: 'SERIAL_NAME',
      type: 'string',
      initializer: `${result.className}_SERIAL_NAME`,
      isStatic: true,
      isReadonly: true,
    });
    Logger.debug(`为类 ${classDecl.getName()} 添加静态属性 serialName`);
  }

  private generateConvertToSendableMethod(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    // 检查是否已存在该方法
    if (classDecl.getMethod('toSendable')) {
      Logger.warn(`类 ${result.className} 已存在toSendable方法，跳过生成`);
      return;
    }

    const isSendable = result.decorators.serializable?.generateSendable;

    if (!isSendable) {
      // 如果不需要生成Sendable类，返回undefined
      classDecl.addMethod({
        name: 'toSendable',
        returnType: 'undefined',
        statements: ['return undefined']
      });
      return;
    }

    let returnType = `Sendable${result.className}`;
    if (result.generics.parameters.length > 0) {
      returnType += `<${result.generics.parameters.join(', ')}>`;
    }
    // 生成方法体
    const methodBody = this.generateConvertToSendableMethodBody(result, returnType);
    classDecl.addMethod({
      name: 'toSendable',
      returnType: returnType,
      statements: [methodBody]
    });
  }

  private generateToJsonMethod(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    // 检查是否已存在该方法
    if (classDecl.getMethod('toJson')) {
      Logger.warn(`类 ${result.className} 已存在toJson方法，跳过生成`);
      return;
    }

    const methodBody = 'return TJSON.toString(this, typeKey)';

    classDecl.addMethod({
      name: 'toJson',
      returnType: 'string',
      parameters: [{
        name: 'typeKey',
        type: 'TypeKey',
        hasQuestionToken: true
      }],
      statements: [methodBody]
    });
  }

  private registerImports(): void {
    this.importManager.registerJsonImports(['ITSerializable', 'TJSON']);

    this.importManager.registerCoreImports(['TypeKey', 'Serializable', 'Encoder', 'SerialDescriptor']);
  }

  // ============= toSendable方法生成 =============

  private generateConvertToSendableMethodBody(classAnalysis: ClassAnalysis, returnType: string): string {
    const constructorProps: PropertyAnalysis[] = [];
    // 遍历 constructorParams 按顺序处理
    classAnalysis.constructorParams.forEach((cp) => {
      // 查找 classAnalysis.properties 中是否存在该属性
      const matchingProperty = classAnalysis.properties.find((p) => p.name === cp.name);

      // 如果找到匹配的属性，按顺序添加到 constructorProps
      if (matchingProperty) {
        constructorProps.push({
          ...matchingProperty,
          type: {
            ...matchingProperty.type,
            // 使用 constructorParam 中的 isOptional
            isOptional: cp.isOptional,
          }
        });
      }
    });

    const assignmentProps = classAnalysis.properties.filter((p) => {
      return classAnalysis.constructorParams.every((cp) => cp.name !== p.name);
    });
    const statements: string[] = [];

    // 生成构造函数调用
    const constructorCall = this.generateConstructorCall(constructorProps, returnType);
    statements.push(`const sendable = ${constructorCall};`);

    // 生成属性赋值语句
    if (assignmentProps.length > 0) {
      statements.push('');
      statements.push('// 非构造函数属性赋值');
      assignmentProps.forEach((prop) => {
        const assignment = this.generatePropertyAssignment(prop);
        statements.push(`sendable.${prop.name} = ${assignment};`);
      });
    }

    statements.push('');
    statements.push('return sendable;');

    return statements.join('\n');
  }

  private generateConstructorCall(constructorProps: PropertyAnalysis[], returnType: string): string {
    if (constructorProps.length === 0) {
      return `new ${returnType}()`;
    }

    const args = constructorProps.map(prop => {
      return this.generatePropertyConversion(prop, 'this.');
    }).join(', ');

    return `new ${returnType}(${args})`;
  }

  private generatePropertyAssignment(prop: PropertyAnalysis): string {
    return this.generatePropertyConversion(prop, 'this.');
  }

  private generatePropertyConversion(prop: PropertyAnalysis, prefix: string): string {
    const sourceValue = `${prefix}${prop.name}`;
    if (prop.type.kind === PropertyKind.UNKNOWN) {
      // UNKNOWN只接跳过
      return sourceValue;
    }
    const registry = TypeHandlerRegistry.getInstance();
    const handler = registry.getHandlerForKind(prop.type.kind);

    // TO_SENDABLE: 普通对象 -> Sendable对象
    return handler.generatePropertyConversion(prop.type, sourceValue, ConversionDirection.TO_SENDABLE);
  }
}
